import { Injectable } from '@nestjs/common';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { isEmpty, isNil } from 'lodash';
import { EntityManager, In, Like, Repository } from 'typeorm';
import { PagerDto } from '~/common/dto/pager.dto';
import { ROOT_ROLE_ID } from '~/constants/system.constant';
import { paginate } from '~/helper/paginate';
import { Pagination } from '~/helper/paginate/pagination';
import { MenuEntity } from '~/modules/system/menu/menu.entity';
import { RoleEntity } from '~/modules/system/role/role.entity';
import { RoleDto, RoleQueryDto, RoleUpdateDto } from './role.dto';
import { UserService } from '~/modules/user/user.service';
import { UserRole } from './role.constant';
import { ErrorEnum } from '~/constants/error-code.constant';

@Injectable()
export class RoleService {
  constructor(
    @InjectRepository(RoleEntity)
    private roleRepository: Repository<RoleEntity>,
    @InjectRepository(MenuEntity)
    private menuRepository: Repository<MenuEntity>,
    @InjectEntityManager() private entityManager: EntityManager,
    private readonly userService: UserService
  ) {}

  /**
   * 列举所有角色：除去超级管理员
   */
  async findAll({ page, pageSize }: PagerDto): Promise<Pagination<RoleEntity>> {
    return paginate(this.roleRepository, { page, pageSize });
  }

  /**
   * 查询角色列表
   */
  async list({
    page,
    pageSize,
    name,
    value,
    remark,
    status,
  }: RoleQueryDto): Promise<Pagination<RoleEntity>> {
    const queryBuilder = await this.roleRepository.createQueryBuilder('role').where({
      ...(name ? { name: Like(`%${name}%`) } : null),
      ...(value ? { value: Like(`%${value}%`) } : null),
      ...(remark ? { remark: Like(`%${remark}%`) } : null),
      ...(!isNil(status) ? { status } : null),
    });

    return paginate<RoleEntity>(queryBuilder, {
      page,
      pageSize,
    });
  }

  /**
   * 判断角色是否存在
   */
  async hasRole(rid: number): Promise<boolean> {
		const role = await this.getRoleById(rid);

    if (isNil(role)) {
      return false;
    }

    return true;
  }

  /**
   * 根据角色ID查找角色信息
   */
  async getRoleById(rid: number): Promise<RoleEntity> {
    return this.roleRepository.findOneBy({ id: rid });
  }

  /**
   * 根据角色获取角色信息
   */
  async info(id: number) {
    const info = await this.roleRepository
      .createQueryBuilder('role')
      .where({
        id,
      })
      .getOne();

    const menus = await this.menuRepository.find({
      where: { roles: { id } },
      select: ['id'],
    });

    return { ...info, menuIds: menus.map((m) => m.id) };
  }

  async delete(id: number): Promise<void> {
    if (id === ROOT_ROLE_ID) throw new Error('不能删除超级管理员');
    await this.roleRepository.delete(id);
  }

  /**
   * 增加角色
   */
  async create({ ...data }: RoleDto): Promise<{ roleId: number }> {
    const role = await this.roleRepository.save({
      ...data,
      // menus: menuIds
      //   ? await this.menuRepository.findBy({ id: In(menuIds) })
      //   : [],
    });

    return { roleId: role.id };
  }

  /**
   * 更新角色信息
   * 如果传入的menuIds为空，则清空sys_role_menus表中存有的关联数据，参考新增
   */
  async update(id, { ...data }: RoleUpdateDto): Promise<void> {
    await this.roleRepository.update(id, data);
    await this.entityManager.transaction(async (manager) => {
      const role = await this.roleRepository.findOne({ where: { id } });
      // role.menus = menuIds?.length
      //   ? await this.menuRepository.findBy({ id: In(menuIds) })
      //   : []
      await manager.save(role);
    });
  }

  /**
   * 根据用户id查找角色信息
   */
  async getRoleIdsByUser(uid: number): Promise<number | null> {
    const user = await this.userService.getAccountInfo(uid);

    if (!isEmpty(user.role) && user.role.id) {
      return user.role.id;
    }

    return null;
  }

  async getRoleValues(ids: number[]): Promise<string[]> {
    return (
      await this.roleRepository.findBy({
        id: In(ids),
      })
    ).map((r) => r.value);
  }

  async isAdminRoleByUser(uid: number): Promise<boolean> {
    const user = await this.userService.getAccountInfo(uid);

    const roleName = user?.role?.name ?? '';

    return roleName === UserRole.ADMIN || roleName === UserRole.SUPER_ADMIN;
  }

  async hasAdminRole(rid: number): Promise<boolean> {
    const role = await this.roleRepository.findOneBy({
      id: rid,
    });

    if (!role) {
      return false;
    }

    return role.name === UserRole.ADMIN || role.name === UserRole.SUPER_ADMIN;

    // return rids.includes(ROOT_ROLE_ID);
  }

  /**
   * 根据角色ID查找是否有关联用户
   */
  async checkUserByRoleId(id: number): Promise<boolean> {
    return this.roleRepository.exist({
      where: {
        // users: {
        //   roles: { id },
        // },
      },
    });
  }

  /**
   * 通过超级管理员创建角色
   */
  async createByRoot(data: RoleDto): Promise<RoleEntity> {
    return this.roleRepository.save(data);
  }

  async getRolePermissions(rid: number): Promise<MenuEntity[]> {
    const role = await this.roleRepository.findOne({
      where: { id: rid },
      relations: ['menus'],
    });

    return role.menus;
  }

  async bindUserToRoles(userId: number, roleId: number): Promise<void> {
    const hasRow: boolean = await this.hasRole(roleId);

    if (!hasRow) {
      throw new Error(ErrorEnum.ROLE_NOT_FOUND);
    }

    const role = await this.getRoleById(roleId);

    await this.userService.bindRole(userId, role);
  }
}
